package com.luxk.db.common;

/* TODO 공통 코드로 이관하고 각 모듈에서 가져다 쓰는 구조로 변경 */

import java.io.PrintStream;
import java.io.PrintWriter;

import com.luxk.db.lock.LockMode;

public class SimpleObjectCache implements ObjectCache, Dumpable {
	private String name;
	protected int bucketCount = 0;
	protected BucketHeader[] buckets = null;
	
	public SimpleObjectCache(String name, int bucketCount)
			throws Exception {
		// 2의 누승인지 확인
		if((bucketCount & (bucketCount-1)) != 0)
			throw new Exception(
					"bucket count(" + bucketCount + ") must be power of 2");
		this.bucketCount = bucketCount;
		this.buckets = new BucketHeader[this.bucketCount];
		for(int i = 0; i < this.bucketCount; i++) {
			this.buckets[i] = new BucketHeader();
		}
	}

	@Override
	public String getName() {
		return this.name;
	}

	@Override
	public void load() throws ImpactException {
		assert false;
	}

	@Override
	public void put(int id1, int id2, Object obj) {
		int idx = (id1+id2) & (this.bucketCount-1);
		BucketElement elem = new BucketElement();
		elem.id1 = id1;
		elem.id2 = id2;
		elem.state = BucketElement.ElementState.VALID;
		elem.obj = obj;
		
		synchronized(this.buckets[idx]) {
			elem.next = this.buckets[idx].head;
			this.buckets[idx].head = elem;
		}
	}

	@Override
	public Object get(int id1, int id2) {
		int idx = (id1+id2) & (this.bucketCount-1);
		Object obj = null;
		synchronized(this.buckets[idx]) {
			BucketElement e;
			for(e = this.buckets[idx].head; e != null; e = e.next) {
				if(e.id1 == id1 && e.id2 == id2) {
					obj = e.obj;
					break;
				}
			}
		}
		return obj;
	}

	@Override
	public Object search(Object cond) {
		assert false;
		return null;
	}

	@Override
	public Object getLocked(int id1, int id2, LockMode mode) {
		assert false;
		return null;
	}

	@Override
	public Object searchLocked(Object cond, LockMode mode) {
		assert false;
		return null;
	}
	
	public void unlock(int id1, int id2) {
		assert false;
	}

	@Override
	public Object refresh(int id1, int id2) {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public Object invalidate(int id1, int id2) {
		int idx = (id1+id2) & (this.bucketCount-1);
		Object obj = null;
		synchronized(this.buckets[idx]) {
			BucketElement e, prev;
			for(e = this.buckets[idx].head, prev = null; e != null;
					prev = e, e = e.next) {
				if(e.id1 == id1 && e.id2 == id2) {
					e.state = BucketElement.ElementState.INVALID;
					obj = e.obj;
					e.obj = null;
					
					if(prev != null)
						prev.next = e.next;
					else
						this.buckets[idx].head = e.next;
					
					break;
				}
			}
		}
		return obj;
	}

	@Override
	public void invalidate() {
		for(int i = 0; i < this.bucketCount; i++) {
			synchronized(this.buckets[i]) {
				BucketElement e, prev;
				for(e = this.buckets[i].head, prev = null; e != null;
						prev = e, e = e.next) {
					e.state = BucketElement.ElementState.INVALID;
					e.obj = null;
					
					if(prev != null)
						prev.next = e.next;
					else
						this.buckets[i].head = e.next;
				}
			}		
		}
	}

	public void dump(PrintWriter out) {}
	public void dump(PrintStream out) {}
	public void dump(StringBuffer out) {}

}

class BucketHeader {
	public BucketElement head = null;
}

class BucketElement {
	
	public enum ElementState {
		VALID,
		INVALIDATING,
		INVALID
	};
	
	BucketElement next = null;
	
	int id1 = -1;
	int id2 = -1;
	
	ElementState state = ElementState.INVALID;
	Object obj = null;
}
